package neuralmusic.brain.ga;


import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import neuralmusic.brain.RTScheduler;
import neuralmusic.brain.module.BasicModule;
import neuralmusic.brain.module.Brain;
import neuralmusic.brain.module.Connection;
import neuralmusic.brain.module.Scheduler;
import neuralmusic.brain.module.Module;
import neuralmusic.brain.module.Neuron;

public class GABrainFactory {

	public static Gene encode(Brain brain) {
		Gene gene = new Gene();

		List<Connection> connections = brain.getConnections();
		int nConnect = connections.size();
		float[] weights = new float[nConnect];

		for (int i = 0; i < nConnect; i++) {
			weights[i] = connections.get(i).weight;
		}

		gene.add(new Token(Type.CONNECTIONS, weights));

	
		gene.add(new Token(Type.BRAIN, "Brain"));
		gene.add(new Token(Type.INPUTS,
				brain.toIntArray(brain.getInputs())));
		gene.add(new Token(Type.OUTPUTS, brain.toIntArray(brain
				.getOutputs())));
	
	
		

		for (Module m : brain.getModules()) {
			Token tok = new Token(Type.MODULE,  m.getName());
			gene.add(tok);
			gene.add(new Token(Type.INPUTS,
					brain.toIntArray(m.getInputs())));
			gene.add(new Token(Type.OUTPUTS, brain.toIntArray(m
					.getOutputs())));
		
					
			
			for (Neuron n : m.getNeurons()) {
				tok = new Token(Type.NEURON,null);
				gene.add(tok);
				gene.addAll(n.getParams(brain));
			}
			
			gene.add(new Token(Type.TERM,null));
			
		
		}

		return gene;
	}

	static List<Token> parseToTerm(Iterator<Token> iter) {
		List<Token> list = new ArrayList<Token>();
		while (iter.hasNext()) {
			Token tok = iter.next();
			if (tok.type == Type.TERM)
				break;
			list.add(tok);
		}
		return list;
	}

	public static Brain decode(Gene gene) {
		

		Random rand=new Random();
		
		Brain brain = new Brain(rand);

		Iterator<Token> iter = gene.iterator();
		int inputs[];
		int outputs[];
	
		Token tok;		
		tok = iter.next();
		assert(tok.type ==Type.CONNECTIONS);
		float[] weights = (float[]) tok.data;
		brain.createConnections(weights);
		
		
		tok = iter.next();
		assert(tok.type==Type.BRAIN);
		
		tok = iter.next();
		assert(tok.type==Type.INPUTS);
		inputs=(int [])tok.data;
		brain.inputs=brain.connectionFromIntArray(inputs);
		
		tok = iter.next();
		assert(tok.type ==Type.OUTPUTS);
		
		outputs=(int [])tok.data;
		brain.outputs=brain.connectionFromIntArray(outputs);

		while (iter.hasNext()) {		
			tok = iter.next();
			if (tok.type == Type.TERM) break;
		//	tok.print(System.out);
			assert(tok.type==Type.MODULE);
			Module module=parseModule(tok.data.toString(),iter,brain);
			brain.addModule(module);
		}
		return brain;
	}
	
	public static Module parseModule(String name,Iterator<Token> iter,Brain brain){
	
		BasicModule module = new BasicModule(name);
		Neuron neuron;
		int inputs[];
		int outputs[];
		
		while (iter.hasNext()) {
			Token tok = iter.next();
			switch (tok.type) {
		
			case NEURON:
				neuron = new Neuron();
				List<Token> params = parseToTerm(iter);
				neuron.buildFromParams(params,brain);
				module.neurons.add(neuron);
				break;
				
			case TERM:
				return module;	
				
				
			case INPUTS:
				inputs=(int [])tok.data;
				module.inputs=brain.connectionFromIntArray(inputs);
				break;
				
			case OUTPUTS:
				outputs=(int [])tok.data;
				module.outputs=brain.connectionFromIntArray(outputs);
				break;
				
				
			}
		}
		assert(false);
		return module;

	}

	public static void diff(Gene g1, Gene g2) {

		Iterator<Token> i1 = g1.iterator();
		Iterator<Token> i2 = g2.iterator();

		PrintStream out = System.out;
		while (i1.hasNext() && i2.hasNext()) {

			Token t1 = i1.next();
			Token t2 = i2.next();
			t1.print(out);
			t2.print(out);

		}
	

	}

}
